package com.capsulode.excel.conversion.impl;


import com.capsulode.excel.conversion.Converter;
import com.capsulode.excel.exception.CellTypeNotExpectException;
import com.capsulode.excel.exception.ConversionFailException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.RichTextString;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;

/**
 * This converter remains cell original excel type as mapping java class.
 */
public class ObjectConverter implements Converter<Object> {
    public static final ObjectConverter DEFAULT_INSTANCE = new ObjectConverter();

    @Override
    public Object convert(Cell cell) throws CellTypeNotExpectException {
        if (CellType.BLANK.equals(cell.getCellTypeEnum())) {
            return null;
        }
        return getCellValue(cell);
    }

    private Object getCellValue(Cell cell) throws CellTypeNotExpectException {
        CellType type = cell.getCellTypeEnum();
        switch (type) {
            case BOOLEAN:
                return cell.getBooleanCellValue();
            case STRING:
                String trim = cell.getStringCellValue().trim();
                return trim.isEmpty() ? null : trim;
            case NUMERIC:
                return cell.getNumericCellValue();
            case BLANK:
                return null;
            default:
                throw new CellTypeNotExpectException(cell.getRowIndex(), cell.getColumnIndex());
        }
    }

    @Override
    public void serialize(Object value, Cell cell) throws ConversionFailException, CellTypeNotExpectException {
        if (value instanceof Boolean) {
            cell.setCellValue((Boolean) value);
            return;
        }
        if (value instanceof Date) {
            cell.setCellValue((Date) value);
            return;
        }
        if (value instanceof Calendar) {
            cell.setCellValue((Calendar) value);
            return;
        }
        if (value instanceof LocalDate) {
            Instant instant = ((LocalDate) value)
                    .atStartOfDay()
                    .atZone(ZoneId.systemDefault())
                    .toInstant();
            cell.setCellValue(Date.from(instant));
            return;
        }
        if (value instanceof LocalDateTime) {
            Instant instant = ((LocalDateTime) value)
                    .atZone(ZoneId.systemDefault())
                    .toInstant();
            cell.setCellValue(Date.from(instant));
            return;
        }
        if (value instanceof RichTextString) {
            cell.setCellValue((RichTextString) value);
            return;
        }
        if (value instanceof Number) {
            cell.setCellValue(((Number) value).doubleValue());
            return;
        }
        cell.setCellValue(value.toString());
    }
}
